/* -*-C-*-
 ##############################################################################
 #
 # File:        trice/src/filter.c
 # RCS:         "@(#)$Revision: 1.13 $ $Date: 94/03/08 11:04:37 $"
 # Description: Routines for configuring filter parameters on a E1430 module.
 # Author:      Doug Passey
 # Created:     
 # Language:    C
 # Package:     E1430
 # Status:      "@(#)$State: Exp $"
 #
 # (C) Copyright 1992, Hewlett-Packard Company, all rights reserved.
 #
 ##############################################################################
 #
 # Please add additional comments here
 #
 # Revisions:
 #
 ##############################################################################
*/

#include <stdio.h>
#include <math.h>

#include "trice.h"
#include "err1430.h"

#ifndef lint
const char filter_fileId[] = "$Header: filter.c,v 1.13 94/03/08 11:04:37 mikea Exp $";
#endif

/*****************************************************************************
 *
 * Get bits for decimation filter output mode.
 * Returns 0 if all ok, else return negative error number.
 *
 ****************************************************************************/
SHORTSIZ16 i1430_get_deci_output_bits(SHORTSIZ16 output, SHORTSIZ16 *bitsPtr)
{
  switch(output) {
    case E1430_ONEPASS:
      *bitsPtr = DATA_FORMAT_FILTER_ONEPASS;
      break;
    case E1430_MULTIPASS:
      *bitsPtr = DATA_FORMAT_FILTER_MULTIPASS;
      break;
    default:
      return (i1430_Error(ERR1430_ILLEGAL_FILTER_PASS_MODE, NULL, NULL));
  }

  return (0);
}


/*****************************************************************************
 *
 * Get bits for decimation filter state.
 * Returns 0 if all ok, else return negative error number.
 *
 ****************************************************************************/
SHORTSIZ16 i1430_get_deci_state_bits(SHORTSIZ16 state, SHORTSIZ16 *bitsPtr)
{
  switch(state) {
    case E1430_DECIMATION_ON:
      *bitsPtr = DATA_FORMAT_DECIMATE_ON;
      break;
    case E1430_DECIMATION_OFF:
      *bitsPtr = DATA_FORMAT_DECIMATE_OFF;
      break;
    default:
      return (i1430_Error(ERR1430_ILLEGAL_DECIMATE_MODE, NULL, NULL));
  }

  return (0);
}


/*****************************************************************************
 *
 * Get bits for decimation passtag.
 * Returns 0 if all ok, else return negative error number.
 *
 ****************************************************************************/
SHORTSIZ16 i1430_get_deci_passtag_bits(SHORTSIZ16 tag, SHORTSIZ16 *bitsPtr)
{
  switch(tag) {
    case E1430_PASS_TAG_24:
      *bitsPtr = DATA_FORMAT_PASSTAG_24;
      break;
    case E1430_PASS_TAG_32:
      *bitsPtr = DATA_FORMAT_PASSTAG_32;
      break;
    default:
      return (i1430_Error(ERR1430_ILLEGAL_PASS_TAG, NULL, NULL));
  }

  return (0);
}


/*****************************************************************************
 *
 * Set decimation filter bandwidth.
 * Returns 0 if all ok, else return negative error number.
 *
 ****************************************************************************/
SHORTSIZ16 i1430_get_deci_bandwidth_bits(SHORTSIZ16 bandwidth, SHORTSIZ16 *bitsPtr)
{
  if(bandwidth < 0 || bandwidth > 24) {	/* bandwidth outside of limits */
    return (i1430_Error(ERR1430_ILLEGAL_FILTER_BANDWIDTH, NULL, NULL));
  }else{
    *bitsPtr = bandwidth << DATA_FORMAT_PASSOUT_BIT_SHIFT;
    return (0);
  }
}


/*****************************************************************************
 *
 * Set decimation filter parameters.
 * Returns 0 if all ok, else return negative error number.
 *
 ****************************************************************************/
SHORTSIZ16 e1430_set_decimation_filter(SHORTSIZ16 groupID, SHORTSIZ16 level,
	SHORTSIZ16 state , SHORTSIZ16 output, SHORTSIZ16 tag)
{
  SHORTSIZ16 modSetupBits, bits;
  SHORTSIZ16 error;
  SHORTSIZ16 mask;
  SHORTSIZ16 bw;
  SHORTSIZ16 filter;
  LONGSIZ32 blocksize;

  /* get current blocksize before possible ONEPASS/MULTIPASS change which
   * could change the size of an individual data point 
   */
  error = e1430_get_blocksize(groupID, &blocksize);
  if(error) return (error);
 
  /* don't allow level to be 24 if decimate is on */
  if(level >= 24) {
   if(state == E1430_DECIMATION_ON) {
     bw = 23;
   }else{
     bw = 24;
   }
  }else{
   bw = level;
  }

  if(bw) {	/* if decimation filter is on, also turn on zoom filter */
    filter = ZOOM_CONTROL_FILTER_ON;
    bw--;			/* zoom filter already decimating once */
  }else{
    filter = ZOOM_CONTROL_FILTER_BYPASS;
  }

  error =  i1430_pause_meas(groupID);
  if(error) return (error);

  error = i1430_update_group_module_bits(groupID, E1430_ZOOM_CONTROL_REG, 
				ZOOM_CONTROL_FILTER_MASK, filter);
  if(error) return (error);

  /* get bits for decimation output */
  error = i1430_get_deci_output_bits(output, &bits);
  if(error) return (error);
  modSetupBits = bits;

  /* get bits for decimation filter*/
  error = i1430_get_deci_state_bits(state, &bits);
  if(error) return (error);
  modSetupBits |= bits;

  /* get bits for decimation bandwidth */
  error = i1430_get_deci_bandwidth_bits(bw, &bits);
  if(error) return (error);
  modSetupBits |= bits;

  /* get bits for pass tag*/
  error = i1430_get_deci_passtag_bits(tag, &bits);
  if(error) return (error);
  modSetupBits |= bits;

  mask = DATA_FORMAT_PASSOUT_MASK & DATA_FORMAT_PASSTAG_MASK &
		DATA_FORMAT_FILTER_MULTIPASS_MASK & DATA_FORMAT_DECIMATE_MASK;

  error = i1430_update_group_module_bits(groupID, E1430_DATA_FORMAT_REG,
					mask, modSetupBits);
  if(error) return(error);

  error = i1430_update_group_module_bits(groupID, E1430_TRIGGER_PASSOUT_REG,
			 	TRIGGER_PASSOUT_MASK, bw);

  /* set register blocksize bits to reflect possible ONEPASS/MULTIPASS change */
  error = i1430_get_blocksize_bits(groupID, blocksize, &bits);
  if(error) return (error);
       
  error = i1430_update_group_module_bits(groupID, E1430_TRIGGER_BLOCKSIZE_REG, 
				TRIGGER_BLOCKSIZE_BLOCK_MASK, bits);
  if(error) return(error);

  return(i1430_continue_meas(groupID));
}


/*****************************************************************************
 *
 * Set decimation state of module group, <groupID>, to the
 * value contained in <state>.
 * Returns 0 if all ok, else return negative error number.
 *
 ****************************************************************************/
SHORTSIZ16 e1430_set_decimation_state(SHORTSIZ16 groupID, SHORTSIZ16 state)
{
  SHORTSIZ16 bits, error;
  SHORTSIZ16 analysisBw, triggerBw;

  error = i1430_get_deci_state_bits(state, &bits);
  if(error) return (error);
  
  error =  i1430_pause_meas(groupID);
  if(error) return (error);

  error = i1430_update_group_module_bits(groupID, E1430_DATA_FORMAT_REG,
					DATA_FORMAT_DECIMATE_MASK, bits);
  if(error) return (error);
  
  error = e1430_get_decimation_bandwidth(groupID, &analysisBw);
  if(error) return(error);

  error = e1430_get_trigger_bandwidth(groupID, &triggerBw);
  if(error) return(error);

  /* don't allow bandwidth to be 24 if decimate is on */
  if(state == E1430_DECIMATION_ON) {
    if(analysisBw == 24) {
      analysisBw = 23;
    }

    if(triggerBw == 24) {
      triggerBw = 23;
    }
  }

  error = e1430_set_decimation_bandwidth(groupID, analysisBw, triggerBw);
  if(error) return(error);

  return(i1430_continue_meas(groupID));
}


/*****************************************************************************
 *
 * Set decimation output of module group, <groupID>, to the
 * value contained in <output>.
 * Returns 0 if all ok, else return negative error number.
 *
 ****************************************************************************/
SHORTSIZ16 e1430_set_decimation_output(SHORTSIZ16 groupID, SHORTSIZ16 output)
{
  SHORTSIZ16 bits, error;
  LONGSIZ32 blocksize;

  /* get current blocksize before possible ONEPASS/MULTIPASS change which
   * could change the size of an individual data point 
   */
  error = e1430_get_blocksize(groupID, &blocksize);
  if(error) return (error);
 
  error = i1430_get_deci_output_bits(output, &bits);
  if(error) return (error);
  
  error =  i1430_pause_meas(groupID);
  if(error) return (error);

  error = i1430_update_group_module_bits(groupID, E1430_DATA_FORMAT_REG,
				DATA_FORMAT_FILTER_MULTIPASS_MASK, bits);
  if(error) return (error);
  
  /* set register blocksize bits to reflect possible ONEPASS/MULTIPASS change */
  error = i1430_get_blocksize_bits(groupID, blocksize, &bits);
  if(error) return (error);
       
  error = i1430_update_group_module_bits(groupID, E1430_TRIGGER_BLOCKSIZE_REG, 
				TRIGGER_BLOCKSIZE_BLOCK_MASK, bits);
  if(error) return(error);

  return(i1430_continue_meas(groupID));
}


/*****************************************************************************
 *
 * Set decimation bandwidths of module group, <groupID>, to the
 * value contained in <analysisBw> and <triggerBw>.
 * Returns 0 if all ok, else return negative error number.
 *
 ****************************************************************************/
SHORTSIZ16 e1430_set_decimation_bandwidth(SHORTSIZ16 groupID, SHORTSIZ16 analysisBw,
							SHORTSIZ16 triggerBw)
{
  SHORTSIZ16 bits, error, state, filter;

  /* it is illegal to have one of the filters set to 0 if the other is not */
  if((!analysisBw && triggerBw) || (!triggerBw && analysisBw)) {
    return(i1430_Error(ERR1430_ILLEGAL_FILTER_BW, NULL, NULL));
  }

  error = e1430_get_decimation_state(groupID, &state);
  if(error) return(error);

  /* don't allow bandwidth to be 24 if decimate is on */
  if(analysisBw >= 24) {
    if(state == E1430_DECIMATION_ON) {
      analysisBw = 23;
    }else{
      analysisBw = 24;
    }
  }

  if(triggerBw >= 24) {
    if(state == E1430_DECIMATION_ON) {
      triggerBw = 23;
    }else{
      triggerBw = 24;
    }
  }

  if(analysisBw || triggerBw) {	/* if bandwidth != 0, turn on zoom filter */
    filter = ZOOM_CONTROL_FILTER_ON;
    analysisBw--;			/* zoom already filtered once */
    triggerBw--;
  }else{
    filter = ZOOM_CONTROL_FILTER_BYPASS;
  }

  error =  i1430_pause_meas(groupID);
  if(error) return (error);

  error = i1430_update_group_module_bits(groupID, E1430_ZOOM_CONTROL_REG, 
				ZOOM_CONTROL_FILTER_MASK, filter);
  if(error) return (error);

  error = i1430_get_deci_bandwidth_bits(analysisBw, &bits);
  if(error) return (error);
  
  error = i1430_update_group_module_bits(groupID, E1430_DATA_FORMAT_REG,
					DATA_FORMAT_PASSOUT_MASK, bits);
  if(error) return (error);
  
  error = i1430_update_group_module_bits(groupID, E1430_TRIGGER_PASSOUT_REG,
			 	TRIGGER_PASSOUT_MASK, triggerBw);
  if(error) return (error);
  
  return(i1430_continue_meas(groupID));
}


/*****************************************************************************
 *
 * Set decimation passtag of module group, <groupID>, to the
 * value contained in <bw>.
 * Returns 0 if all ok, else return negative error number.
 *
 ****************************************************************************/
SHORTSIZ16 e1430_set_decimation_passtag(SHORTSIZ16 groupID, SHORTSIZ16 passtag)
{
  SHORTSIZ16 bits, error;

  error = i1430_get_deci_passtag_bits(passtag, &bits);
  if(error) return (error);
  
  error =  i1430_pause_meas(groupID);
  if(error) return (error);

  error = i1430_update_group_module_bits(groupID, E1430_DATA_FORMAT_REG,
					DATA_FORMAT_PASSTAG_MASK, bits);
  if(error) return (error);
  
  return(i1430_continue_meas(groupID));
}


/*****************************************************************************
 *
 * Return decimation state of module with <index> in e1430_modStates array.
 * Returns 0 if all ok, else return negative error number.
 *
 ****************************************************************************/
SHORTSIZ16 i1430_get_deci_state_index(SHORTSIZ16 index)
{
  switch(e1430_modStates[index].dataFormat & ~DATA_FORMAT_DECIMATE_MASK) {
    case DATA_FORMAT_DECIMATE_ON:
      return (E1430_DECIMATION_ON);
    case DATA_FORMAT_DECIMATE_OFF:
      return (E1430_DECIMATION_OFF);
    default:
      return (i1430_Error(ERR1430_ILLEGAL_DECIMATE_MODE, NULL, NULL));
  }
}


/*****************************************************************************
 *
 * Returns the decimation state of the module group, <groupID>, into
 * the variable pointed to by <statePtr>.  
 * Returns 0 if OK, returns ERR1430_PARAMETER_UNEQUAL if the source is
 * not the same for all modules in the group.
 *
 ****************************************************************************/
SHORTSIZ16 e1430_get_decimation_state(SHORTSIZ16 groupID, SHORTSIZ16 *statePtr)
{ 
  return (i1430_get_short_parm(groupID, i1430_get_deci_state_index, 
				"decimation state", statePtr));
}
 

/*****************************************************************************
 *
 * Return decimation output of module with <index> in e1430_modStates array.
 * Returns 0 if all ok, else return negative error number.
 *
 ****************************************************************************/
SHORTSIZ16 i1430_get_deci_output_index(SHORTSIZ16 index)
{
  switch(e1430_modStates[index].dataFormat & ~DATA_FORMAT_FILTER_MULTIPASS_MASK) {
    case DATA_FORMAT_FILTER_MULTIPASS:
      return (E1430_MULTIPASS);
    case DATA_FORMAT_FILTER_ONEPASS:
      return (E1430_ONEPASS);
    default:
      return (i1430_Error(ERR1430_ILLEGAL_FILTER_PASS_MODE, NULL, NULL));
  }
}


/*****************************************************************************
 *
 * Returns the decimation output of the module group, <groupID>, into
 * the variable pointed to by <outputPtr>.  
 * Returns 0 if OK, returns ERR1430_PARAMETER_UNEQUAL if the source is
 * not the same for all modules in the group.
 *
 ****************************************************************************/
SHORTSIZ16 e1430_get_decimation_output(SHORTSIZ16 groupID, SHORTSIZ16 *outputPtr)
{ 
  return (i1430_get_short_parm(groupID, i1430_get_deci_output_index, 
				"decimation output", outputPtr));
}
 

/*****************************************************************************
 *
 * Return decimation bandwidth of module with <index> in e1430_modStates array.
 * Returns 0 if all ok, else return negative error number.
 *
 ****************************************************************************/
SHORTSIZ16 i1430_get_decimation_bw_index(SHORTSIZ16 index)
{
  SHORTSIZ16 bw;

  bw = (e1430_modStates[index].dataFormat & ~DATA_FORMAT_PASSOUT_MASK) >> 
					DATA_FORMAT_PASSOUT_BIT_SHIFT;
  if((e1430_modStates[index].zoomControl & ~ZOOM_CONTROL_FILTER_MASK) ==
	ZOOM_CONTROL_FILTER_ON) {
   bw++;
  }

  return (bw);
}


/*****************************************************************************
 *
 * Returns the decimation bandwidth of the module group, <groupID>, into
 * the variable pointed to by <bandwidthPtr>.  
 * Returns 0 if OK, returns ERR1430_PARAMETER_UNEQUAL if the source is
 * not the same for all modules in the group.
 *
 ****************************************************************************/
SHORTSIZ16 e1430_get_decimation_bandwidth(SHORTSIZ16 groupID, 
						SHORTSIZ16 *bandwidthPtr)
{ 
  return (i1430_get_short_parm(groupID, i1430_get_decimation_bw_index, 
				"decimation bandwidth", bandwidthPtr));
}
 

/*****************************************************************************
 *
 * Return decimation passtag of module with <index> in e1430_modStates array.
 * Returns 0 if all ok, else return negative error number.
 *
 ****************************************************************************/
SHORTSIZ16 i1430_get_pass_tag_index(SHORTSIZ16 index)
{
  switch(e1430_modStates[index].dataFormat & ~DATA_FORMAT_PASSTAG_MASK) {
    case DATA_FORMAT_PASSTAG_24:
      return (E1430_PASS_TAG_24);
    case DATA_FORMAT_PASSTAG_32:
      return (E1430_PASS_TAG_32);
    default:
      return (i1430_Error(ERR1430_ILLEGAL_PASS_TAG, NULL, NULL));
  }
}


/*****************************************************************************
 *
 * Returns the decimation passtag of the module group, <groupID>, into
 * the variable pointed to by <passtagPtr>.  
 * Returns 0 if OK, returns ERR1430_PARAMETER_UNEQUAL if the source is
 * not the same for all modules in the group.
 *
 ****************************************************************************/
SHORTSIZ16 e1430_get_decimation_passtag(SHORTSIZ16 groupID, SHORTSIZ16 *passtagPtr)
{ 
  return (i1430_get_short_parm(groupID, i1430_get_pass_tag_index, 
				"decimation passtag", passtagPtr));
}
 

/*****************************************************************************
 *
 * Returns trigger bandwidth for module with <index> in e1430_modStates array.
 * not in one of the internal trigger modes, return 0.0.
 *
 ****************************************************************************/
SHORTSIZ16 i1430_get_trigger_bw_index(SHORTSIZ16 index)
{
  SHORTSIZ16 bw;

  bw = e1430_modStates[index].trigPassout & ~TRIGGER_PASSOUT_MASK;
  if((e1430_modStates[index].zoomControl & ~ZOOM_CONTROL_FILTER_MASK) ==
	ZOOM_CONTROL_FILTER_ON) {
   bw++;
  }

  return (bw);
}


/*****************************************************************************
 *
 * Returns the trigger bandwidth of the module group, <groupID>, into
 * the variable pointed to by <bandwidthPtr>.  
 * Returns 0 if OK, returns ERR1430_PARAMETER_UNEQUAL if the bandwidth is
 * not the same for all modules in the group.
 *
 ****************************************************************************/
SHORTSIZ16 e1430_get_trigger_bandwidth(SHORTSIZ16 groupID, SHORTSIZ16 *bandwidthPtr)
{ 
  return (i1430_get_short_parm(groupID, i1430_get_trigger_bw_index, 
				"trigger bandwidth", bandwidthPtr));
}
 

